package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.product.service.TestService;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Author atguigu-mqx
 * @Description TODO
 * @Date 2023/8/22 11:51
 * @Version 1.0
 */
@Service
public class TestServiceImpl implements TestService {

    /*
    1.  在缓存中设置一个key set num = 0;
    2.  通过redis工具类来获取 num 数据
        true:   让这个num+1，写回缓存
        false:  return;
     */

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;


    @Override
    public String readLock() {
        //  获取读写锁对象
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("myLock");
        //  获取到读锁
        RLock lock = rwlock.readLock();
        //  给锁加个过期时间
        lock.lock(10,TimeUnit.SECONDS);
        String msg = this.redisTemplate.opsForValue().get("msg");
        //  解锁
        //  lock.unlock();
        //  返回数据
        return msg;
    }

    @Override
    public String writeLock() {
        //  获取读写锁对象
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("myLock");
        //  获取到写锁
        RLock lock = rwlock.writeLock();
        //  给锁加个过期时间
        lock.lock(10,TimeUnit.SECONDS);
        this.redisTemplate.opsForValue().set("msg",UUID.randomUUID().toString());
        //  解锁
        //  lock.unlock();
        //  返回数据
        return "写入完成...";
    }

    @Override
    public void testLock() throws InterruptedException {
        //  获取锁对象
        RLock lock = redissonClient.getLock("lock");
        //  上锁
          lock.lock();
        //  锁的过期时间是10s;
          lock.lock(10,TimeUnit.SECONDS);
        //  线程的最大等待时间{线程超过这个时间放弃执行}，锁的过期时间，时间单位
        boolean result = lock.tryLock(1, 10, TimeUnit.SECONDS);
        if (result){
            //  获取锁成功
            try {
                //  业务逻辑
                //  获取数据
                String num = this.redisTemplate.opsForValue().get("num");
                if (StringUtils.isEmpty(num)){
                    return;
                }
                //  +1 写回缓存.
                int number = Integer.parseInt(num);
                this.redisTemplate.opsForValue().set("num",String.valueOf(++number));
            } catch (NumberFormatException e) {
                throw new RuntimeException(e);
            } finally {
                //  释放锁资源
                lock.unlock();
            }
        }





        //  执行setnx 命令
        //  Boolean result = this.redisTemplate.opsForValue().setIfAbsent("lock", "ok");
        //  set key value ex timeout nx
        //        String token = UUID.randomUUID().toString();
        //        //  获取锁
        //        Boolean result = this.redisTemplate.opsForValue().setIfAbsent("lock", token,3, TimeUnit.SECONDS);
        //        try {
        //            //  int i = 1/0;
        //            if (result){
        //                //  true : 表示获取到锁了.
        //                //  获取数据
        //                String num = this.redisTemplate.opsForValue().get("num");
        //                if (StringUtils.isEmpty(num)){
        //                    return;
        //                }
        //                //  +1 写回缓存.
        //                int number = Integer.parseInt(num);
        //                this.redisTemplate.opsForValue().set("num",String.valueOf(++number));
        //                //  释放锁资源
        //                //                if (token.equals(this.redisTemplate.opsForValue().get("lock"))){
        //                //                    this.redisTemplate.delete("lock");
        //                //                }
        //                //  可能需要一个守护线程
        //                Thread thread = new Thread(() -> {
        //                    Long expireTime = this.redisTemplate.getExpire("lock");
        //                    if (expireTime < 2) {
        //                        //  续期.
        //                        this.redisTemplate.expire("lock", 5, TimeUnit.SECONDS);
        //                    }
        //                });
        //                //  守护线程。
        //                thread.setDaemon(true);
        //
        //                String scriptText = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
        //                        "then\n" +
        //                        "    return redis.call(\"del\",KEYS[1])\n" +
        //                        "else\n" +
        //                        "    return 0\n" +
        //                        "end";
        //
        //                DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        //                redisScript.setScriptText(scriptText);
        //                redisScript.setResultType(Long.class);
        //                //  redis 要执行lua脚本.
        //                //  第一个参数就是 RedisScript 对象 第二个参数锁的key 第三个参数token
        //                this.redisTemplate.execute(redisScript, Arrays.asList("lock"),token);
        //
        //            } else {
        //                try {
        //                    //    么有获取到锁
        //                    Thread.sleep(300);
        //                    testLock();
        //                } catch (InterruptedException e) {
        //                    throw new RuntimeException(e);
        //                }
        //            }
        //        } catch (RuntimeException e) {
        //            throw new RuntimeException(e);
        //        }

    }
}
